package com.junxonline.instant.util;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.crypto.digest.MD5;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Arrays;

/**
 * 安全工具类
 *
 * @author JunX
 * @date 2021-07-12
 */
public class PasswordUtils {

    /**
     * 随机盐值长度
     */
    private static final int SALT_BYTE_LENGTH = 20;

    /**
     * 编码
     */
    private static final Charset CHARSET = StandardCharsets.UTF_8;

    /**
     * 密码加密
     * @param password 密码
     * @return 加密后的密码
     */
    public static String encrypt(String password) {
        SecureRandom secureRandom = new SecureRandom();
        byte salt[] = new byte[SALT_BYTE_LENGTH];
        secureRandom.nextBytes(salt);
        MD5 md5 = new MD5(salt);
        byte[] digest = md5.digest(password, CHARSET);
        // 填充前20个字节为盐值 校验密码时候需要取出
        byte[] pwd = ArrayUtil.addAll(salt, digest);
        return HexUtil.encodeHexStr(pwd);
    }

    /**
     * 校验密码是否正确
     * @param password 密码
     * @param encryptedPassword 加密后的密码
     * @return boolean
     */
    public static boolean valid(String password, String encryptedPassword) {
        byte[] encryptedPwd = HexUtil.decodeHex(encryptedPassword);
        // 取出前20个字节盐值
        byte[] salt = ArrayUtil.sub(encryptedPwd, 0, SALT_BYTE_LENGTH);
        // 20字节后为真正MD5后密码
        byte[] pwd = ArrayUtil.sub(encryptedPwd, SALT_BYTE_LENGTH, encryptedPwd.length);
        MD5 md5 = new MD5(salt);
        byte[] digest = md5.digest(password, CHARSET);
        return Arrays.equals(digest, pwd);
    }

    public static void main(String[] args) {
        String password = "96e79218965eb72c92a549dd5a330112";
        String password2 = DigestUtil.md5Hex("123456");
        String encryptedPassword = encrypt(password);
        String encryptedPassword2 = encrypt(password);
        System.out.println("password2 => " + password2);
        System.out.println("生成不可逆16进制加密密码 => " + encryptedPassword);
        System.out.println("生成不可逆16进制加密密码2 => " + encryptedPassword2);
        System.out.println("校验登录密码是否正常 => " + valid(password, encryptedPassword));
        System.out.println("校验登录密码是否正常 => " + valid(password, encryptedPassword2));
        System.out.println("原始密码追加内容后校验登录密码是否正确 => " + valid(password + "663", encryptedPassword));
    }

}
